package walletsyslogic

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go.uber.org/zap"
	"navi-mumbai/app/rpc/model/pg/usercenter"
	"navi-mumbai/app/rpc/model/pg/wallet"
	pbuser "navi-mumbai/app/rpc/usercenter/pb"
	"navi-mumbai/common/key/dbkey"
	"navi-mumbai/common/key/userkey"
	"navi-mumbai/common/key/walletkey"
	"navi-mumbai/common/utils"
	"navi-mumbai/common/xerr"

	"navi-mumbai/app/rpc/wallet/internal/svc"
	"navi-mumbai/app/rpc/wallet/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateWithdrawResultLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateWithdrawResultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateWithdrawResultLogic {
	return &UpdateWithdrawResultLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// 更新提现结果
func (l *UpdateWithdrawResultLogic) UpdateWithdrawResult(in *pb.UpdateWithdrawResultReq) (*pb.UpdateWithdrawResultResp, error) {
	defer utils.RecoverPanic()

	var wf *wallet.UserWithdrawFlow
	var err error
	wf, err = l.svcCtx.UserWithdrawFlowModel.FindOne(l.ctx, in.FlowNo)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		if err == wallet.ErrNotFound {
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowNotFound, "not found")
		}
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	// 检查状态
	switch in.State {
	case walletkey.WithdrawFlowStateStart:
		if wf.State != walletkey.WithdrawFlowStateNotAudit {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
		}

		if err = l.updateAuditPass(in, wf); err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, err
		}

	case walletkey.WithdrawFlowStateSuccess, walletkey.WithdrawFlowStateFailed:
		if wf.State != walletkey.WithdrawFlowStateNotAudit && wf.State != walletkey.WithdrawFlowStateStart {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
		}

		if err = l.updateState(in, wf); err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, err
		}
		// 如果提现支付失败，则需要把钱退回给用户
		if in.State == walletkey.WithdrawFlowStateFailed {
			l.Logger.Infof("Withdrawal failed to return balance. in: %+v", in)
			if err = l.returnBalance(wf); err != nil {
				l.Logger.Errorf("err == ", zap.Error(err))
				return nil, err
			}
		}

	case walletkey.WithdrawFlowStateAuditReject:
		if wf.State != walletkey.WithdrawFlowStateNotAudit && wf.State != walletkey.WithdrawFlowStateFailed {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
		}
		if err = l.reject(in, wf); err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, err
		}
	default:
		l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletFlowStateNotAllow, "state error")
	}

	sInMoneyAmount := decimal.NewFromInt(wf.MoneyAmount).Div(decimal.NewFromInt(100)).StringFixedBank(2)

	// 先不走mq通知，后续再优化
	//l.after(wf.Uid, in.State, walletkey.GetMoneyNameByMoneyType(wf.MoneyType), sInMoneyAmount, in.Remark)
	l.afterInsertNotifyMsg(wf.Uid, in.State, walletkey.GetMoneyNameByMoneyType(wf.MoneyType), sInMoneyAmount, in.Remark)

	return &pb.UpdateWithdrawResultResp{}, nil
}

// 提现成功之后，插入通知消息
func (l *UpdateWithdrawResultLogic) afterInsertNotifyMsg(uid int64, state int64, moneyName, moneyAmount, remark string) {
	title := ""
	var msgContent userkey.UserNotifyMsgContent1
	var msgType int64 = 0
	switch state {
	case walletkey.WithdrawFlowStateStart:
		title = userkey.UserNotifyMsgTitleWithdrawAuditPass04EnIn
		msgType = userkey.UserNotifyMsgTypeWithdrawAuditPass04
		msgContent = userkey.UserNotifyMsgContent1{
			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentWithdrawAuditPass04EnIn, moneyAmount, moneyName),
			Url:      "",
			PagePath: "",
		}
	case walletkey.WithdrawFlowStateAuditReject:
		title = userkey.UserNotifyMsgTitleWithdrawAuditReject05EnIn
		msgType = userkey.UserNotifyMsgTypeWithdrawAuditReject05
		msgContent = userkey.UserNotifyMsgContent1{
			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentWithdrawAuditReject05EnIn, remark),
			Url:      "",
			PagePath: "",
		}
	case walletkey.WithdrawFlowStateSuccess:
		title = userkey.UserNotifyMsgTitleWithdrawPaySuccess06EnIn
		msgType = userkey.UserNotifyMsgTypeWithdrawPaySuccess06
		msgContent = userkey.UserNotifyMsgContent1{
			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentWithdrawPaySuccess06EnIn, moneyAmount, moneyName),
			Url:      "",
			PagePath: "",
		}
	case walletkey.WithdrawFlowStateFailed:
		title = userkey.UserNotifyMsgTitleWithdrawPayFailed07EnIn
		msgType = userkey.UserNotifyMsgTypeWithdrawPayFailed07
		msgContent = userkey.UserNotifyMsgContent1{
			Text:     userkey.UserNotifyMsgContentWithdrawPayFailed07EnIn,
			Url:      "",
			PagePath: "",
		}
	default:
		return
	}
	var cBuf []byte
	cBuf, err := json.Marshal(msgContent)
	if err != nil {
		l.Logger.Errorf("afterInsertNotifyMsg after json.Marshal(msgContent) err:%v", err)
		return
	}
	in := &pbuser.AddUserNotifyMsgReq{
		Uid:        uid,
		Title:      title,
		MsgType:    msgType,
		MsgContent: string(cBuf),
	}
	_, err = l.AddUserNotifyMsg(in)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		l.Logger.Errorf("afterInsertNotifyMsg error. uid: %d", uid)
	}
	l.Logger.Errorf("afterInsertNotifyMsg sucess.")
}

// 新增通知消息

// 新增通知消息
func (l *UpdateWithdrawResultLogic) AddUserNotifyMsg(in *pbuser.AddUserNotifyMsgReq) (*pbuser.AddUserNotifyMsgResp, error) {
	err := l.svcCtx.UserAccountModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		unm := usercenter.UserNotifyMsg{
			Uid:        in.Uid,
			MsgType:    in.MsgType,
			MsgContent: in.MsgContent,
			IsRead:     dbkey.Enable,
			Title:      in.Title,
		}
		l.Logger.Infof("AddUserNotifyMsg. in: %+v", in)
		// 增加消息
		_, err2 := l.svcCtx.UserNotifyMsgModel.InsertTrans(ctx, tx, &unm)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		// 更新消息条数
		err2 = l.svcCtx.UserNotifyMsgStatModel.AddMsgCount(ctx, tx, in.Uid, 1)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		return nil
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}
	return &pbuser.AddUserNotifyMsgResp{}, nil
}

func (l *UpdateWithdrawResultLogic) returnBalance(wf *wallet.UserWithdrawFlow) error {
	// 查询用户钱包
	var uw *wallet.UserWallet
	var err error
	uw, err = l.svcCtx.UserWalletModel.FindOneByUidMoneyType(l.ctx, wf.Uid, wf.MoneyType)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		if err == wallet.ErrNotFound {
			return xerr.NewGrpcErrCodeMsg(xerr.WalletNotFound, "wallet not found")
		}
		return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}
	err = l.svcCtx.UserWalletModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		// 更新钱包余额
		err2 := l.svcCtx.UserWalletModel.AddAmountTrans(ctx, tx, wf.MoneyAmount, uw.Id, uw.Uid, uw.MoneyType)
		if err2 != nil {
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		return nil
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return err
	}
	return nil
}

func (l *UpdateWithdrawResultLogic) updateState(in *pb.UpdateWithdrawResultReq, wf *wallet.UserWithdrawFlow) error {
	// 更新提现流水状态
	err := l.svcCtx.UserWithdrawFlowModel.UpdateState(l.ctx, wf.FlowNo, in.State, in.ExternalFlowNo, in.ErrMsg, in.PayGwFlowNo)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}
	return nil
}

func (l *UpdateWithdrawResultLogic) updateAuditPass(in *pb.UpdateWithdrawResultReq, wf *wallet.UserWithdrawFlow) error {
	// 更新提现流水状态
	err := l.svcCtx.UserWithdrawFlowModel.UpdateAudit(l.ctx, wf.FlowNo, in.State, in.Remark, in.AdminUid)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}
	return nil
}

func (l *UpdateWithdrawResultLogic) reject(in *pb.UpdateWithdrawResultReq, wf *wallet.UserWithdrawFlow) error {
	// 查询用户钱包
	var uw *wallet.UserWallet
	var err error
	uw, err = l.svcCtx.UserWalletModel.FindOneByUidMoneyType(l.ctx, wf.Uid, wf.MoneyType)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		if err == wallet.ErrNotFound {
			return xerr.NewGrpcErrCodeMsg(xerr.WalletNotFound, "wallet not found")
		}
		return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	err = l.svcCtx.UserWalletModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		// 更新钱包余额
		err2 := l.svcCtx.UserWalletModel.AddAmountTrans(ctx, tx, wf.MoneyAmount, uw.Id, uw.Uid, uw.MoneyType)
		if err2 != nil {
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		// 创建提现流水
		err2 = l.svcCtx.UserWithdrawFlowModel.UpdateAuditTrans(ctx, tx, wf.FlowNo, in.State, in.Remark, in.AdminUid)
		if err2 != nil {
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		return nil
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return err
	}
	return nil
}

//func (l *UpdateWithdrawResultLogic) after(uid int64, state int64, moneyName, moneyAmount, remark string) {
//	var kqMsg kqmsg.KqAddUserNotifyMsg
//	var msgContent userkey.UserNotifyMsgContent1
//	switch state {
//	case walletkey.WithdrawFlowStateStart:
//		kqMsg = kqmsg.KqAddUserNotifyMsg{
//			Uid:     uid,
//			Title:   userkey.UserNotifyMsgTitleWithdrawAuditPass04EnIn,
//			MsgType: userkey.UserNotifyMsgTypeWithdrawAuditPass04,
//		}
//
//		msgContent = userkey.UserNotifyMsgContent1{
//			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentWithdrawAuditPass04EnIn, moneyAmount, moneyName),
//			Url:      "",
//			PagePath: "",
//		}
//	case walletkey.WithdrawFlowStateAuditReject:
//		kqMsg = kqmsg.KqAddUserNotifyMsg{
//			Uid:     uid,
//			Title:   userkey.UserNotifyMsgTitleWithdrawAuditReject05EnIn,
//			MsgType: userkey.UserNotifyMsgTypeWithdrawAuditReject05,
//		}
//
//		msgContent = userkey.UserNotifyMsgContent1{
//			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentWithdrawAuditReject05EnIn, remark),
//			Url:      "",
//			PagePath: "",
//		}
//	case walletkey.WithdrawFlowStateSuccess:
//		kqMsg = kqmsg.KqAddUserNotifyMsg{
//			Uid:     uid,
//			Title:   userkey.UserNotifyMsgTitleWithdrawPaySuccess06EnIn,
//			MsgType: userkey.UserNotifyMsgTypeWithdrawPaySuccess06,
//		}
//
//		msgContent = userkey.UserNotifyMsgContent1{
//			Text:     fmt.Sprintf(userkey.UserNotifyMsgContentWithdrawPaySuccess06EnIn, moneyAmount, moneyName),
//			Url:      "",
//			PagePath: "",
//		}
//	case walletkey.WithdrawFlowStateFailed:
//		kqMsg = kqmsg.KqAddUserNotifyMsg{
//			Uid:     uid,
//			Title:   userkey.UserNotifyMsgTitleWithdrawPayFailed07EnIn,
//			MsgType: userkey.UserNotifyMsgTypeWithdrawPayFailed07,
//		}
//
//		msgContent = userkey.UserNotifyMsgContent1{
//			Text:     userkey.UserNotifyMsgContentWithdrawPayFailed07EnIn,
//			Url:      "",
//			PagePath: "",
//		}
//	default:
//		return
//	}
//
//	var cBuf []byte
//	cBuf, err := json.Marshal(msgContent)
//	if err != nil {
//		l.Logger.Errorf("UpdateWithdrawResultLogic after json.Marshal(msgContent) err:%v", err)
//		return
//	}
//	kqMsg.MsgContent = string(cBuf)
//
//	var kqMsgBuf []byte
//	kqMsgBuf, err = json.Marshal(kqMsg)
//	if err != nil {
//		l.Logger.Errorf("UpdateWithdrawResultLogic after json.Marshal(kqMsg) err:%v", err)
//		return
//	}
//
//	err = l.svcCtx.KqAddUserNotifyMsgClient.Push(string(kqMsgBuf))
//	if err != nil {
//		l.Logger.Errorf("UpdateWithdrawResultLogic after Push err:%v", err)
//		return
//	}
//	return
//}
